<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Three.js 球体贴图展示</title>
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/controls/OrbitControls.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/loaders/GLTFLoader.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/loaders/DRACOLoader.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            background: linear-gradient(135deg, #1a2a6c, #2c3e50, #4a235a);
            font-family: 'Arial', sans-serif;
            overflow: hidden;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        #container {
            position: relative;
            width: 100%;
            height: 100vh;
            box-shadow: 0 0 30px rgba(0, 0, 0, 0.7);
        }

        #info {
            position: absolute;
            top: 20px;
            width: 100%;
            text-align: center;
            color: white;
            z-index: 100;
            text-shadow: 0 0 10px rgba(0, 0, 0, 0.8);
            pointer-events: none;
        }

        #title {
            font-size: 2.2em;
            font-weight: bold;
            margin-bottom: 5px;
            color: #3498db;
            letter-spacing: 3px;
        }

        #instructions {
            font-size: 1.1em;
            opacity: 0.85;
            margin-top: 15px;
        }



        .progress {
            height: 100%;
            width: 0%;
            background: #3498db;
            transition: width 0.3s ease;
        }

        .credit {
            position: absolute;
            bottom: 20px;
            width: 100%;
            text-align: center;
            color: rgba(255, 255, 255, 0.6);
            font-size: 0.9em;
        }

        .stars {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: -1;
        }

        .star {
            position: absolute;
            background: white;
            border-radius: 50%;
        }

        input[type="color"] {
            width: 50px;
            height: 50px;
            padding: 0;
            border: none;
            cursor: pointer;
        }
    </style>
</head>

<body>
    <div id="container">
        <div id="info">
            <div id="title">球体贴图展示</div>
            <div id="instructions">鼠标拖动旋转 · 滚轮缩放</div>
        </div>

        <div class="stars" id="stars"></div>

        <button style="position: fixed;right:220px;top:20px;padding: 10px 20px;cursor: pointer;"
            onclick="changeMaterial(1)">切换材质1</button>
        <button style="position: fixed;right:120px;top:20px;padding: 10px 20px;cursor: pointer;"
            onclick="changeMaterial(2)">切换材质2</button>
        <button style="position: fixed;right:20px;top:20px;padding: 10px 20px;cursor: pointer;"
            onclick="changeMaterial(3)">切换材质3</button>

        <input type="color" id="targetColor" value="#ff0000"
            style="position: fixed;right:130px;top:80px;padding: 1px 2px;cursor: pointer;width: 100px;height: 40px;">
        <button style="position: fixed;right:20px;top:80px;padding: 10px 20px;cursor: pointer;"
            onclick="changeColr(3)">修改颜色</button>
    </div>

    <script>
        // 创建背景星空
        function createStars() {
            const starsContainer = document.getElementById('stars');
            const starsCount = 150;

            for (let i = 0; i < starsCount; i++) {
                const star = document.createElement('div');
                star.classList.add('star');

                // 随机位置
                const x = Math.random() * 100;
                const y = Math.random() * 100;

                // 随机大小 (0.5px - 2px)
                const size = Math.random() * 1.5 + 0.5;

                // 随机透明度
                const opacity = Math.random() * 0.8 + 0.2;

                star.style.left = `${x}%`;
                star.style.top = `${y}%`;
                star.style.width = `${size}px`;
                star.style.height = `${size}px`;
                star.style.opacity = opacity;

                // 闪烁动画
                const duration = Math.random() * 5 + 5;
                star.style.animation = `twinkle ${duration}s infinite alternate`;

                starsContainer.appendChild(star);
            }

            // 添加闪烁动画关键帧
            const style = document.createElement('style');
            style.innerHTML = `
                @keyframes twinkle {
                    0% { opacity: 0.2; }
                    100% { opacity: ${Math.random() * 0.8 + 0.4}; }
                }
            `;
            document.head.appendChild(style);
        }

        createStars();

        // 初始化Three.js场景
        let scene, camera, renderer, ball, clouds, controls;
        // 模型加载器
        // const dracoLoader = new THREE.DRACOLoader()
        // dracoLoader.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/')
        // loader.setDRACOLoader(dracoLoader)
        const loader = new THREE.GLTFLoader()

        let ballmodel = null  // 球体材质
        // 初始化场景
        function init(gltf) {
            // 创建场景
            scene = new THREE.Scene();

            // 创建相机
            camera = new THREE.PerspectiveCamera(
                45,
                window.innerWidth / window.innerHeight,
                0.1,
                10000
            );
            camera.position.z = 20;

            // 创建渲染器
            renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.shadowMap.enabled = true;
            document.getElementById('container').appendChild(renderer.domElement);

            // 添加光源
            const ambientLight = new THREE.AmbientLight(0x404040, 3);
            scene.add(ambientLight);

            const directionalLight = new THREE.DirectionalLight(0xffffff, 1.2);
            directionalLight.position.set(10, 5, 7);
            directionalLight.castShadow = true;
            scene.add(directionalLight);

            // 添加模型
            ballmodel = gltf.scene
            ballmodel.traverse((child) => {
                if (child.isMesh) {
                    child.castShadow = true
                    child.receiveShadow = true
                }
            })
            scene.add(ballmodel)
            traverseAndModifyMaterials(ballmodel, './1.jpg')

            // 添加星星背景
            const starGeometry = new THREE.BufferGeometry();
            const starVertices = [];

            for (let i = 0; i < 10000; i++) {
                const x = (Math.random() - 0.5) * 2000;
                const y = (Math.random() - 0.5) * 2000;
                const z = (Math.random() - 0.5) * 2000;

                starVertices.push(x, y, z);
            }

            starGeometry.setAttribute('position', new THREE.Float32BufferAttribute(starVertices, 3));
            const starMaterial = new THREE.PointsMaterial({
                color: 0xffffff,
                size: 1.2,
                sizeAttenuation: false
            });

            const starField = new THREE.Points(starGeometry, starMaterial);
            scene.add(starField);

            // 添加轨道控制
            controls = new THREE.OrbitControls(camera, renderer.domElement);
            controls.enableDamping = true;
            controls.dampingFactor = 0.05;
            controls.minDistance = 8;
            controls.maxDistance = 50;

            // 响应窗口大小变化
            window.addEventListener('resize', onWindowResize);

            // 开始动画
            animate();
        }
        // 窗口大小调整
        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }

        // 动画循环
        function animate() {
            requestAnimationFrame(animate);

            // 球体自转
            // ball.rotation.y += 0.001;

            controls.update();
            renderer.render(scene, camera);
        }
        // 加载模型
        loader.load(
            './static/BAHOUEX.glb',
            (gltf) => {
                gltf.scene.scale.set(0.05, 0.05, 0.05);
                // 当所有纹理加载完成后初始化场景
                init(gltf)
            }
        )
        function traverseAndModifyMaterials(object, url, png) {
            const textureLoader = new THREE.TextureLoader();
            const texture1 = textureLoader.load(url);
            object.traverse((child) => {
                if (child.isMesh) {
                    // 创建新材质
                    if (!png) {
                        const newMaterial = new THREE.MeshStandardMaterial({
                            map: new THREE.TextureLoader().load(url)
                        });
                        child.material = newMaterial
                    } else {
                        const texture2 = textureLoader.load(png);
                        const customMaterial = new THREE.ShaderMaterial({
                            uniforms: {
                                texture1: { value: texture1 },
                                texture2: { value: texture2 },
                                blendFactor: { value: 0.5 }
                            },
                            vertexShader: `
                            varying vec2 vUv;
                            void main() {
                            vUv = uv;
                            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
                            }
                        `,
                            fragmentShader: `
                            uniform sampler2D texture1;
                            uniform sampler2D texture2;
                            uniform float blendFactor;
                            varying vec2 vUv;
                            
                            void main() {
                            vec4 tex1 = texture2D(texture1, vUv);
                            vec4 tex2 = texture2D(texture2, vUv); // 双倍UV实现细节重复
                            gl_FragColor = mix(tex1, tex2, step(0.5, tex2.a));
                            }
                        `
                        });
                        child.material = customMaterial
                    }
                }
            });
        }

        // 修改材质
        function changeMaterial(i) {
            switch (i) {
                case 1:
                    traverseAndModifyMaterials(ballmodel, './1.jpg')
                    break;
                case 2:
                    traverseAndModifyMaterials(ballmodel, './2.jpg')
                    break;
                case 3:
                    traverseAndModifyMaterials(ballmodel, './3.jpg')
                    break;
            }
        }
        /**
* 修改Base64图片中不透明部分的颜色
* @param {string} base64Image - Base64格式的图片数据
* @param {string} newColor - 要替换的新颜色(十六进制格式，如'#ff0000')
* @param {number} [threshold=0] - 透明度阈值(0-255)，低于此值视为透明
* @param {function} [callback] - 处理完成后的回调函数
* @returns {Promise<string>} 返回处理后的Base64图片
*/
        function changeBase64ImageColor(base64Image, newColor, threshold = 0, callback) {
            return new Promise((resolve) => {
                const img = new Image();
                img.onload = function () {
                    const canvas = document.createElement('canvas');
                    const ctx = canvas.getContext('2d');
                    canvas.width = img.width;
                    canvas.height = img.height;

                    // 绘制原始图像
                    ctx.drawImage(img, 0, 0);

                    // 获取像素数据
                    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                    const data = imageData.data;

                    // 将新颜色从十六进制转换为RGB
                    const hex = newColor.replace('#', '');
                    const r = parseInt(hex.substring(0, 2), 16);
                    const g = parseInt(hex.substring(2, 4), 16);
                    const b = parseInt(hex.substring(4, 6), 16);

                    // 修改不透明像素的颜色
                    for (let i = 0; i < data.length; i += 4) {
                        // 检查alpha通道(透明度)
                        if (data[i + 3] > threshold) {
                            data[i] = r;     // R
                            data[i + 1] = g; // G
                            data[i + 2] = b; // B
                            // 保持原始alpha值不变
                        }
                    }

                    // 将修改后的像素数据放回canvas
                    ctx.putImageData(imageData, 0, 0);

                    // 转换为Base64
                    const newBase64 = canvas.toDataURL('image/png');

                    if (callback) callback(newBase64);
                    resolve(newBase64);
                };

                img.src = base64Image;
            });
        }
        let png1 = ""
        // 修改颜色
        async function changeColr() {
            const targetColor = document.getElementById('targetColor');
            const hexColor = targetColor.value;
            await changeBase64ImageColor(png1, hexColor).then(newImage => {
                traverseAndModifyMaterials(ballmodel, './1.jpg', newImage)
            });
        }

    </script>
</body>

</html>